/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
 * Copyright (c) 2024
 *
 * 本程序是自由软件；您可以根据自由软件基金会发布的GNU通用公共许可证
 * 第2版来重新发布和/或修改本程序；
 *
 * 本程序的发布是希望它能发挥作用，但不提供任何保证；甚至不包含
 * 对适销性或特定用途适用性的暗示保证。详见GNU通用公共许可证
 * 获取更多细节。
 *
 * 您应该已收到GNU通用公共许可证的副本；如果没有，请写信给
 * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "dgrv2-dynamic-priority-queue-disc.h"

#include "dgr-tags.h"

#include "ns3/drop-tail-queue.h"
#include "ns3/ipv4-header.h"
#include "ns3/ipv4-queue-disc-item.h"
#include "ns3/log.h"
#include "ns3/net-device-queue-interface.h"
#include "ns3/socket.h"
#include "ns3/timestamp-tag.h"

NS_LOG_COMPONENT_DEFINE("DGRv2DynamicPriorityQueueDisc");

namespace ns3
{

NS_OBJECT_ENSURE_REGISTERED(DGRv2DynamicPriorityQueueDisc);

TypeId
DGRv2DynamicPriorityQueueDisc::GetTypeId(void)
{
    static TypeId tid =
        TypeId("ns3::DGRv2DynamicPriorityQueueDisc")
            .SetParent<QueueDisc>()
            .SetGroupName("Ddr")
            .AddConstructor<DGRv2DynamicPriorityQueueDisc>()
            .AddAttribute("MaxSizePriority0",
                          "优先级0队列的最大容量(字节)",
                          UintegerValue(100 * 1024), // 100KB
                          MakeUintegerAccessor(&DGRv2DynamicPriorityQueueDisc::GetMaxSizePriority0, &DGRv2DynamicPriorityQueueDisc::SetMaxSizePriority0),
                          MakeUintegerChecker<uint32_t>())
            .AddAttribute("MaxSizePriority1",
                          "优先级1队列的最大容量(字节)",
                          UintegerValue(250 * 1024), // 250KB
                          MakeUintegerAccessor(&DGRv2DynamicPriorityQueueDisc::GetMaxSizePriority1, &DGRv2DynamicPriorityQueueDisc::SetMaxSizePriority1),
                          MakeUintegerChecker<uint32_t>())
            .AddAttribute("MaxSizePriority2",
                          "优先级2队列的最大容量(字节)",
                          UintegerValue(500 * 1024), // 500KB
                          MakeUintegerAccessor(&DGRv2DynamicPriorityQueueDisc::GetMaxSizePriority2, &DGRv2DynamicPriorityQueueDisc::SetMaxSizePriority2),
                          MakeUintegerChecker<uint32_t>())
            .AddAttribute("MaxSizePriority3",
                          "优先级3队列的最大容量(字节)",
                          UintegerValue(750 * 1024), // 750KB
                          MakeUintegerAccessor(&DGRv2DynamicPriorityQueueDisc::GetMaxSizePriority3, &DGRv2DynamicPriorityQueueDisc::SetMaxSizePriority3),
                          MakeUintegerChecker<uint32_t>())
            .AddAttribute("MaxSizePriority4",
                          "优先级4队列的最大容量(字节)",
                          UintegerValue(1000 * 1024), // 1MB
                          MakeUintegerAccessor(&DGRv2DynamicPriorityQueueDisc::GetMaxSizePriority4, &DGRv2DynamicPriorityQueueDisc::SetMaxSizePriority4),
                          MakeUintegerChecker<uint32_t>())
            .AddAttribute("UseDynamicPriority",
                          "是否使用基于剩余时间的动态优先级",
                          BooleanValue(true),
                          MakeBooleanAccessor(&DGRv2DynamicPriorityQueueDisc::m_useDynamicPriority),
                          MakeBooleanChecker())
            .AddAttribute("QueueDelayRef",
                          "参考队列延迟",
                          TimeValue(MilliSeconds(10)),
                          MakeTimeAccessor(&DGRv2DynamicPriorityQueueDisc::m_queueDelayRef),
                          MakeTimeChecker());
    return tid;
}

DGRv2DynamicPriorityQueueDisc::DGRv2DynamicPriorityQueueDisc()
    : QueueDisc(QueueDiscSizePolicy::MULTIPLE_QUEUES, QueueSizeUnit::BYTES)
{
    NS_LOG_FUNCTION(this);
    m_queueDelay = 0.0;
    for (int i = 0; i < 5; i++)
    {
        m_currentSize[i] = 0;
    }
}

DGRv2DynamicPriorityQueueDisc::~DGRv2DynamicPriorityQueueDisc()
{
    NS_LOG_FUNCTION(this);
}

uint32_t
DGRv2DynamicPriorityQueueDisc::GetQueueStatus(void)
{
    NS_LOG_FUNCTION(this);
    uint32_t totalSize = 0;
    for (int i = 0; i < 5; i++)
    {
        totalSize += m_currentSize[i];
    }
    return totalSize;
}

double
DGRv2DynamicPriorityQueueDisc::GetQueueDelay(void)
{
    NS_LOG_FUNCTION(this);
    return m_queueDelay;
}

bool
DGRv2DynamicPriorityQueueDisc::DoEnqueue(Ptr<QueueDiscItem> item)
{
    NS_LOG_FUNCTION(this << item);

    uint32_t index = EnqueueClassify(item);
    uint32_t itemSize = item->GetSize();

    // 检查队列是否已满
    if (m_currentSize[index] + itemSize > m_maxSize[index])
    {
        NS_LOG_LOGIC("队列" << index << "已满，丢弃数据包");
        DropBeforeEnqueue(item, LIMIT_EXCEEDED_DROP);
        return false;
    }

    // 入队数据包
    if (GetInternalQueue(index)->Enqueue(item))
    {
        NS_LOG_LOGIC("数据包入队到队列 " << index);
        m_currentSize[index] += itemSize;

        // 更新队列延迟估计
        double totalSize = 0;
        for (int i = 0; i < 5; i++)
        {
            totalSize += m_currentSize[i];
        }
        m_queueDelay = (totalSize * 8.0) / (10.0 * 1000.0 * 1000.0); // 假设链路速率为10 Mbps

        return true;
    }

    return false;
}

Ptr<QueueDiscItem>
DGRv2DynamicPriorityQueueDisc::DoDequeue(void)
{
    NS_LOG_FUNCTION(this);

    // 严格优先级调度：优先处理高优先级队列
    for (int i = 0; i < 5; i++)
    {
        if (GetInternalQueue(i)->GetNPackets() > 0)
        {
            Ptr<QueueDiscItem> item = StaticCast<QueueDiscItem>(GetInternalQueue(i)->Dequeue());
            if (item != nullptr)
            {
                uint32_t itemSize = item->GetSize();
                m_currentSize[i] -= itemSize;

                // 更新队列延迟估计
                double totalSize = 0;
                for (int j = 0; j < 5; j++)
                {
                    totalSize += m_currentSize[j];
                }
                m_queueDelay =
                    (totalSize * 8.0) / (10.0 * 1000.0 * 1000.0); // 假设链路速率为10 Mbps

                NS_LOG_LOGIC("从队列 " << i << " 出队数据包");
                return item;
            }
        }
    }

    NS_LOG_LOGIC("没有可出队的数据包");
    return nullptr;
}

Ptr<const QueueDiscItem>
DGRv2DynamicPriorityQueueDisc::DoPeek(void) const
{
    NS_LOG_FUNCTION(this);

    for (int i = 0; i < 5; i++)
    {
        if (GetInternalQueue(i)->GetNPackets() > 0)
        {
            return StaticCast<const QueueDiscItem>(GetInternalQueue(i)->Peek());
        }
    }

    return nullptr;
}

bool
DGRv2DynamicPriorityQueueDisc::CheckConfig(void)
{
    NS_LOG_FUNCTION(this);

    if (GetNInternalQueues() == 0)
    {
        NS_LOG_ERROR("DGRv2DynamicPriorityQueueDisc需要5个内部队列");
        return false;
    }

    return true;
}

void
DGRv2DynamicPriorityQueueDisc::InitializeParams(void)
{
    NS_LOG_FUNCTION(this);

    // 初始化队列大小
    for (int i = 0; i < 5; i++)
    {
        m_currentSize[i] = 0;
    }
    m_queueDelay = 0.0;
}

uint32_t
DGRv2DynamicPriorityQueueDisc::EnqueueClassify(Ptr<QueueDiscItem> item)
{
    NS_LOG_FUNCTION(this << item);

    if (!m_useDynamicPriority)
    {
        PriorityTag priorityTag;
        if (item->GetPacket()->PeekPacketTag(priorityTag))
        {
            return 0;
        }
        else
        {
            return 4;
        }
    }
    // 基于剩余时间的动态优先级
    TimestampTag timestampTag;
    BudgetTag budgetTag;
    uint32_t priority = 4; // 默认最低优先级

    if (item->GetPacket()->PeekPacketTag(budgetTag) &&
        item->GetPacket()->PeekPacketTag(timestampTag))
    {
        uint32_t currentTime = Simulator::Now().GetMicroSeconds();
        uint32_t sentTime = timestampTag.GetTimestamp().GetMicroSeconds();
        uint32_t budget = budgetTag.GetBudget();
        uint32_t elapsedTime = currentTime - sentTime;
        uint32_t remainingTime = budget - elapsedTime;

        // 计算剩余时间百分比
        double remainingPercent = 0.0;
        if (budget > 0)
        {
            remainingPercent = static_cast<double>(remainingTime) / budget;
        }
        NS_LOG_LOGIC("数据包预算: " << budget << " 微秒, 已用时间: " << elapsedTime
                             << " 微秒, 剩余时间: " << remainingTime << " 微秒, 剩余百分比: "
                             << remainingPercent * 100 << "%");
        // 根据剩余时间百分比分配优先级
        if (remainingPercent < 0.2)
        {
            priority = 0; // 最高优先级(第1类) - 紧急，剩余时间 < 20%
        }
        else if (remainingPercent < 0.4)
        {
            priority = 1; // 高优先级(第2类) - 紧迫，剩余时间 20-40%
        }
        else if (remainingPercent < 0.6)
        {
            priority = 2; // 中优先级(第3类) - 正常，剩余时间 40-60%
        }
        else if (remainingPercent < 0.8)
        {
            priority = 3; // 低优先级(第4类) - 尽力而为，剩余时间 60-80%
        }
        else
        {
            priority = 4; // 最低优先级(第5类) - 背景流量，剩余时间 > 80%
        }

        // 修复日志输出，将微秒转换为毫秒
        NS_LOG_LOGIC("数据包分类到优先级 "
             << priority << "，剩余时间: " << (remainingTime / 1000.0) << " ms" << "，预算: "
             << (budget / 1000.0) << " ms" << "，剩余百分比: " << remainingPercent * 100 << "%");  }

    return priority;
}

} // namespace ns3
